
`include "common_header.verilog"

//  *************************************************************************
//  File : pfc_rcv_ctl
//  *************************************************************************
//  This program is controlled by a written license agreement.
//  Unauthorized Reproduction or Use is Expressly Prohibited. 
//  Copyright (c) 2009 MoreThanIP.com, Germany
//  Designed by : Daniel Koehler
//  info@morethanip.com
//  *************************************************************************
//               Ethernet MAC Core 
//  *************************************************************************
//  Description: Priority Flow Control (PFC) or Link Pause frame is received.
//               Implement the pause timers and, for link pause, control
//               MAC TX to hold transmission.
//  Version    : $Id: pfc_rcv_ctl.v,v 1.4 2017/05/12 09:23:21 gc Exp $
//  *************************************************************************
module pfc_rcv_ctl (

   reset_rxclk,
   xgmii_rxclk,
   xgmii_rxclk_ena,
   rx_enable,
   pfc_mode_r,
   qtime_r,
   qtime_run,
   pause_quant_val,
   pause_quant_avb,
   rx_pfc_xoff,
   reset_txclk,
   xgmii_txclk,
   xgmii_txclk_ena,
   pause_wait_t,
   pause_cnt_dec_t);

parameter PFC_PRIORITIES = 8; // Set to 8 or 16

input   reset_rxclk;            //  Active High reset for xgmii_rxclk domain
input   xgmii_rxclk;            //  XGMII receive clock      
input   xgmii_rxclk_ena;        //  XGMII receive Clock enable
input   rx_enable;              //  receive datapath enable
input   pfc_mode_r;             //  PFC mode(1) or Link Pause mode (0) (rxclk)
input   qtime_r;                //  pulse when pause time of 1 expired (512 bits) (rxclk)
output   qtime_run;             //  timer is enabled, should generate pulses
input   [(1+16)*PFC_PRIORITIES-1:0] pause_quant_val; // Pause Quanta value from rx path: enable(8)+8*quanta(16)
input   pause_quant_avb;        //  Pause Quanta value available from rx path
output   [PFC_PRIORITIES-1:0] rx_pfc_xoff; //  per class status. bit0 used with link pause.
input   reset_txclk;            //  Active High reset for xgmii_txclk domain
input   xgmii_txclk;            //  XGMII transmit clock      
input   xgmii_txclk_ena;        //  XGMII Transmit Clock enable.
output   pause_wait_t;          //  indicate tx should pause (txclk)
input   pause_cnt_dec_t;        //  MAC tx statemachine is paused, pause counter may decrement now (txclk)

reg     qtime_run; 
wire    [PFC_PRIORITIES-1:0] rx_pfc_xoff; 
wire    pause_wait_t; 

wire    [PFC_PRIORITIES-1:0] pause_on; 
wire    [PFC_PRIORITIES-1:0] cl_quant_avb; //  per class quanta available for loading into counter
wire    [PFC_PRIORITIES-1:0] cl_quant_ena; //  per class quanta enable from frame
wire    lhi; //  logic high

assign lhi = 1'b 1; 

//  extract quanta enable bits from MSBs of the vector
assign cl_quant_ena = pause_quant_val[(PFC_PRIORITIES*16)+:PFC_PRIORITIES]; 

//  indicate if any of the timers is loaded so the global timer should produce pulses
//  ---------------------------------------------------------------------------------
always @(posedge reset_rxclk or posedge xgmii_rxclk)
   begin : process_1
   if (reset_rxclk == 1'b 1)
      begin
      qtime_run <= 1'b 0;	
      end
   else
      begin
        //  CLOCK ENABLE 
      if (xgmii_rxclk_ena == 1'b 1)
         begin
         qtime_run <= |pause_on;
         end
      end
   end

//  indicate running counters per class
assign rx_pfc_xoff = pause_on;

//  Class0 shared with Link pause
//  -----------------------------
//  indicate quanta0 to be loaded when either link pause, or class 0 enabled
assign cl_quant_avb[0] = pfc_mode_r == 1'b 0 & pause_quant_avb == 1'b 1 | 
	                 pfc_mode_r == 1'b 1 & pause_quant_avb == 1'b 1 & cl_quant_ena[0] == 1'b 1 ? 1'b 1 : 1'b 0; 

pause_pfc0_rcv_ctl U_C0 (
          .reset_rxclk(reset_rxclk),
          .xgmii_rxclk(xgmii_rxclk),
          .xgmii_rxclk_ena(xgmii_rxclk_ena),
          .pfc_mode_r(pfc_mode_r),
          .qtime_r(qtime_r),
          .pause_quant_val(pause_quant_val[15:0]),         //  quanta0 shared with link pause quanta
          .pause_quant_avb(cl_quant_avb[0]),
          .pause_on(pause_on[0]),         //  class0/link pause active
          .reset_txclk(reset_txclk),
          .xgmii_txclk(xgmii_txclk),
          .xgmii_txclk_ena(xgmii_txclk_ena),
          .pause_wait_t(pause_wait_t),
          .pause_cnt_dec_t(pause_cnt_dec_t));

//  indicate quanta available per class.
assign cl_quant_avb[PFC_PRIORITIES-1:1] = pause_quant_avb == 1'b 1 && pfc_mode_r == 1'b 1 ? 
                cl_quant_ena[PFC_PRIORITIES-1:1] : {PFC_PRIORITIES-1{1'b0}}; //  Classes 1..(PFC_PRIORITIES-1) are pure class based pause

// Class 1..7 timers
// ---------------------------------------
genvar i;
generate
for (i = 1; i < PFC_PRIORITIES; i=i+1)
begin : U_PFC_CLASS_TIMERS
        pause_tmr U_TMR (
                  .reset     (reset_rxclk              ),
                  .clk       (xgmii_rxclk              ),
                  .clk_ena   (lhi                      ),
                  .qtime     (qtime_r                  ),          //  rx clock domain
                  .dec_ok    (lhi                      ),
                  .quanta_val(pause_quant_val[i*16+:16]),
                  .tload     (cl_quant_avb[i]          ),
                  .twait     (pause_on[i]              )
        );
end
endgenerate

endmodule // module pfc_rcv_ctl
